home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
iguana
/
vts139b
/
lib
/
sounddev.asm
< prev
next >
Wrap
Assembly Source File
|
1993-12-21
|
29KB
|
903 lines
IDEAL
MODEL TPascal
LOCALS @@
JUMPS
P286
DATASEG
MACRO SetBorder r,g,b
MASM
COMMENT %
PUSH DX AX
MOV DX,3C8h
XOR AL,AL
OUT DX,AL
INC DX
IFDIF <&r>,<0>
MOV AL,&r
ENDIF
OUT DX,AL
IFDIF <&g>,<&r>
MOV AL,&g
ENDIF
OUT DX,AL
IFDIF <&b>,<&g>
MOV AL,&b
ENDIF
OUT DX,AL
POP AX DX
%
IDEAL
ENDM
StackSize EQU 1000
DMABufferSize EQU 2048
FinalBufferSize EQU 4096
GLOBAL DevStack : BYTE
GLOBAL DevSS : WORD
GLOBAL DevSP : WORD
GLOBAL OldTimerHandler : DWORD
GLOBAL Sounding : DWORD
GLOBAL SoundLeft : WORD
GLOBAL SystemClockIncr : WORD
GLOBAL SystemClockCount : WORD
GLOBAL PeriodicCount : WORD
GLOBAL PeriodicStart : WORD
GLOBAL PeriodicProc : DWORD
GLOBAL DeviceIdling : BYTE
GLOBAL NumChannels : WORD
GLOBAL BytesPerSample : BYTE
GLOBAL DoBassPower : BYTE
GLOBAL MixMethod : BYTE
GLOBAL DMABufferPtr : DWORD
GLOBAL DMABufferEnd : WORD
GLOBAL DMABuffer : DWORD
GLOBAL DMABufferYet : BYTE
GLOBAL DMAStopped : BYTE
GLOBAL DMAStop : BYTE
GLOBAL DMAIrqWatch : BYTE
GLOBAL FinalBufferPos : WORD
GLOBAL FinalBuffer : WORD
GLOBAL DeviceStartRut : WORD
GLOBAL DeviceRut1 : WORD
GLOBAL DeviceRut2 : WORD
GLOBAL DeviceKickRut : WORD
GLOBAL DeviceFillRut : WORD
GLOBAL TrebleFilterVal_Left : WORD
GLOBAL TrebleFilterMult_Left : WORD
GLOBAL BassFilterVal_Left : WORD
GLOBAL BassFilterMult_Left : WORD
GLOBAL TrebleFilterVal_Right : WORD
GLOBAL TrebleFilterMult_Right : WORD
GLOBAL BassFilterVal_Right : WORD
GLOBAL BassFilterMult_Right : WORD
CODESEG
GLOBAL DoGetBuffer : FAR
GLOBAL GetDMACount : NEAR
GLOBAL InitTimer : FAR
; ┌──────────────────────────────────────────────────────────────────────────┐
; │ │
; │ MACRO: Saturate │
; │ │
; │ Macro that saturates a sample just after an addition. │
; │ │
; │ IN: Reg = Register to be saturated. │
; │ │
; └──────────────────────────────────────────────────────────────────────────┘
MACRO Saturate Reg
LOCAL @@posit, @@nooverf
JNO SHORT @@nooverf
JS SHORT @@posit
MOV Reg,-32767
JMP SHORT @@nooverf
@@posit: MOV Reg,32767
@@nooverf:
ENDM Saturate
INCLUDE "BASSPOW.INC"
INCLUDE "MIXROUTS.INC"
MACRO DevCall DevRut, Segm
JMP [DevRut] ; Segm:
DevRut&Ret:
ENDM
; ┌──────────────────────────────────────────────────────────────────────────┐
; │ │
; │ ROUTINE: DMAFillBuffer │
; │ │
; │ This routine fills a portion of the DMA buffer with the whole buffer of │
; │ samples pointed to by Sounding & SoundLeft. │
; │ │
; │ IN: nothing │
; │ │
; │ OUT: nothing │
; │ │
; │ MODIFIES: AX, BX, CX, DX, SI, DI, ES │
; │ │
; └──────────────────────────────────────────────────────────────────────────┘
DeviceIdCount DB 0
TickCnt DB 0
PUBLIC DMAFillBuffer
DMAFillBuffer:
XOR AL,AL
MOV [CS:DeviceIdCount],AL
CALL CalcNewMixData
MOV CX,[SoundLeft]
MOV AL,[BytesPerSample]
MOV DX,CX
XOR AH,AH
MUL DX
LES DI,[DMABufferPtr]
MOV BX,[DMABufferEnd]
LDS SI,[Sounding]
CLD
ADD AX,DI
CMP AX,BX
JBE SHORT @@end
SUB BX,DI
JZ SHORT @@skip1st
PUSH CX
MOV AX,BX
MOV CL,[SS:BytesPerSample]
XOR CH,CH
XOR DX,DX
DIV CX
MOV CX,AX
PUSH CX
CALL [SS:DeviceFillRut]
POP BX
POP CX
SUB CX,BX
@@skip1st: MOV DI,[WORD PTR SS:DMABuffer]
@@end: CALL [SS:DeviceFillRut]
;MOV AL,[CS:TickCnt]
;XOR AL,255
;MOV [CS:TickCnt],AL
;MOV [ES:DI-1],AL
MOV AX,SS
MOV DS,AX
MOV [WORD PTR DMABufferPtr],DI
RET
; ┌──────────────────────────────────────────────────────────────────────────┐
; │ │
; │ ROUTINE: DMADoGetBuff │
; │ │
; │ This is the main buffer-filling routine for DMA devices. First it calls │
; │ the buffer grabber. Then, it checks to see if the DMA has advanced │
; │ enough to leave space for this buffer. │
; │ │
; │ IN: nothing │
; │ │
; │ OUT: nothing │
; │ │
; │ MODIFIES: AX, BX, CX, DX, SI, DI, ES │
; │ │
; └──────────────────────────────────────────────────────────────────────────┘
PUBLIC DMADoGetBuff
DMADoGetBuff:
MOV AX,[SoundLeft]
MOV BL,[DMABufferYet]
AND BL,BL
JZ SHORT @@1
CALL DoGetBuffer
@@1: MOV BL,1
MOV [DMABufferYet],BL
CMP AX,10
JC SHORT @@end
MOV DL,[BytesPerSample]
XOR DH,DH
MUL DX
PUSH AX
CALL GetDMACount
MOV BX,DMABufferSize
SUB BX,AX
ADD BX,[WORD PTR DMABuffer]
MOV CX,BX
SUB BX,[WORD PTR DMABufferPtr]
JNC SHORT @@2
ADD BX,DMABufferSize
@@2: POP AX
SUB BX,AX
JNC DMAFillBuffer
XOR BL,BL
MOV [DMABufferYet],BL
@@end:
MOV AL,[CS:DeviceIdCount]
CMP AL,20
JNC @@end1
INC [CS:DeviceIdCount]
@@end1:
MOV [DeviceIdling],AL
RET
; MOV [DevSS],SS
; MOV [DevSP],SP
; MOV DX,DS
; MOV SS,DX
; MOV SP,OFFSET DevStack + StackSize
; MOV SS,[DevSS]
; MOV SP,[DevSP]
; ┌──────────────────────────────────────────────────────────────────────────┐
; │ │
; │ ROUTINE: TimerHandler │
; │ │
; │ This is the big routine for non-DMA devices. It is called through │
; │ interrupts from a timer whose period is the sampling period. │
; │ │
; └──────────────────────────────────────────────────────────────────────────┘
PUBLIC TimerHandler
TimerHandler:
CLI ; Just for safety's sake.
; ┌────────────────────────────────────────────┐
; │ Startup: │
; │ │
; │ - Save the registers in the local stack. │
; │ - Set the data segment register. │
; └────────────────────────────────────────────┘
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH DS
MOV AX,SEG Sounding
MOV DS,AX
; ┌──────────────────────────────────────────┐
; │ First, we jump to the device start code. │
; └──────────────────────────────────────────┘
DevCall DeviceStartRut
; ┌───────────────────────────────────────────┐
; │ Check to see if there are samples to use. │
; └───────────────────────────────────────────┘
MOV AX,[SoundLeft]
AND AX,AX
JZ SHORT thAfterProcessingSample
; ┌──────────────────────────────────────────────┐
; │ Decrement the number of samples left in the │
; │ buffer, do the device initialization if any, │
; │ and signal that the device is not idle. │
; └──────────────────────────────────────────────┘
DEC AX
MOV [SoundLeft],AX
DevCall DeviceRut1
XOR BH,BH
MOV [DeviceIdling],BH
; ┌─────────────────────────────────┐
; │ Load the buffer pointer, do the │
; │ mixing and output the sample. │
; └─────────────────────────────────┘
LDS SI,[Sounding]
CALL MixChannels
MOV DX,SEG Sounding
MOV DS,DX
MOV [WORD PTR Sounding],SI
MOV SI,OFFSET FinalBuffer
MOV CX,[FinalBufferPos]
ADD SI,CX
ADD SI,CX
MOV [SI],AX
INC CX
AND CX,FinalBufferSize - 1
MOV [FinalBufferPos],CX
DevCall DeviceRut2
; ┌────────────────────┐
; │ Restore the stack. │
; └────────────────────┘
thAfterProcessingSample:
sti
; ┌────────────────────────────┐
; │ Check if the old interrupt │
; │ routine must be called. │
; └────────────────────────────┘
MOV AX,[SystemClockIncr]
ADD [SystemClockCount],AX
JC SHORT @@SystemClock
; ┌──────────────────────────────────┐
; │ Else, signal the EOI to the PIC. │
; └──────────────────────────────────┘
MOV AL,20h
OUT 20h,AL
@@CheckOutProc:
MOV CX,[PeriodicCount]
JCXZ SHORT @@OutProc
DEC CX
MOV [PeriodicCount],CX
JZ SHORT @@OutProc
MOV AX,[SoundLeft]
AND AX,AX
JZ SHORT @@OutProc
@@exit:
; ┌────────────────────────────────────┐
; │ Do the final stuff: Pop registers. │
; └────────────────────────────────────┘
POP DS
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
IRET
@@SystemClock:
PUSHF
CALL [OldTimerHandler]
JMP SHORT @@CheckOutProc
@@OutProc:
; ┌────────────────────────────────────────────┐
; │ Get a new sample buffer. If there is none, │
; │ signal that the device is in idle state. │
; └────────────────────────────────────────────┘
MOV AL,0
@@outsemaph:
AND AL,AL
JNZ SHORT @@exit
INC AL
MOV [BYTE PTR CS:@@outsemaph-1],AL
MOV AX,[SoundLeft]
AND AX,AX
JNZ SHORT @@NoIdle
CALL CalcNewMixData
PUSH ES
CALL DoGetBuffer
POP ES
CALL CalcNewMixData
MOV AX,[SoundLeft]
AND AX,AX
JNZ SHORT @@NoIdle
INC AH
MOV [DeviceIdling],AH
@@NoIdle:
MOV [BYTE PTR CS:@@outsemaph-1],0
; ┌─────────────────────────────────────────────┐
; │ See if the periodic process must be called. │
; └─────────────────────────────────────────────┘
MOV AX,[PeriodicCount]
AND AX,AX
JNZ SHORT @@NoPeriodic
MOV AX,[PeriodicStart]
MOV [PeriodicCount],AX
; ┌────────────────────────────┐
; │ Call the periodic process. │
; └────────────────────────────┘
PUSH ES
STI
CALL [PeriodicProc]
POP ES
@@NoPeriodic:
JMP SHORT @@exit
; ┌──────────────────────────────────────────────────────────────────────────┐
; │ │
; │ ROUTINE: DMATimerHandler │
; │ │
; │ This is the big routine for DMA devices. It is called through │
; │ interrupts from a timer whose period is a few Hertz (100 for example). │
; │ │
; └──────────────────────────────────────────────────────────────────────────┘
DMASema DB 0
PUBLIC DMATimerHandler
DMATimerHandler:
CLI ; Just for safety's sake.
; ┌─────────────────────────┐
; │ Startup: │
; │ │
; │ - Save the registers. │
; └─────────────────────────┘
PUSHA
PUSH ES
PUSH DS
MOV AX,SEG Sounding
MOV DS,AX
@@DoSystemClock:
; ┌────────────────────────────────────────────────────┐
; │ Check if the old interrupt routine must be called. │
; └────────────────────────────────────────────────────┘
MOV AX,[SystemClockIncr]
ADD [SystemClockCount],AX
JNC SHORT @@NoSysClk
; ┌───────────────┐
; │ If so, do it. │
; └───────────────┘
PUSHF
CALL [OldTimerHandler]
JMP SHORT @@SystemClkDone
@@NoSysClk:
; ┌──────────────────────────────────┐
; │ Else, signal the EOI to the PIC. │
; └──────────────────────────────────┘
MOV AL,20h
OUT 20h,AL
@@SystemClkDone:
CLI
; ┌─────────────────────────────────────────┐
; │ First we check if the DMA operation is │
; │ requested to stop. If so, we signal the │
; │ stopping of the DMA and jump to the old │
; │ IRQ-checking part. │
; └─────────────────────────────────────────┘
MOV AL,[DMAStop]
AND AL,AL
JZ SHORT @@notstop
; MOV [DMAStopped],AL
MOV [DeviceIdling],AL
JMP SHORT @@end
@@notstop:
; ┌─────────────────────────────────────────┐
; │ Now, we check the IRQ watchdog, just in │
; │ case we need to kick the card. │
; └─────────────────────────────────────────┘
MASM
COMMENT #
MOV AL,[DMAIrqWatch]
CMP AL,200
JC SHORT @@notwatch
; CALL [DeviceKickRut]
@@notwatch:
; ┌─────────────────────────────────────────┐
; │ If the device is said to be idle, reset │
; │ the timer. This is to protect the timer │
; │ period from being modified. │
; └─────────────────────────────────────────┘
MOV AL,[DeviceIdling]
AND AL,AL
JZ SHORT @@notidling
; CALL InitTimer
@@notidling:
; ┌────────────────────────────────────────┐
; │ Signal that the device is not idling, │
; │ and fill a bit more of the DMA buffer. │
; └────────────────────────────────────────┘
#
IDEAL
MOV AL,[CS:DMASema]
AND AL,AL
JNZ @@end
INC [CS:DMASema]
STI
@@loop:
PUSH DS
MOV AX,0B800h
MOV DS,AX
INC [WORD PTR DS:90*4];
POP DS
MOV [DevSS],SS
MOV [DevSP],SP
MOV DX,DS
MOV SS,DX
MOV SP,OFFSET DevStack + StackSize
XOR AL,AL
MOV [DeviceIdling],AL
;SetBorder 0, 63, 63
STI
CALL DMADoGetBuff
CLI
;SetBorder 0, 0, 63
; ┌─────────────────────────────────────┐
; │ Call the periodic process and exit. │
; └─────────────────────────────────────┘
STI
CALL [PeriodicProc]
CLI
MOV SS,[DevSS]
MOV SP,[DevSP]
MOV AL,[CS:DeviceIdCount]
AND AL,AL
; JZ @@loop
DEC [CS:DMASema]
@@end:
; ┌────────────────────────────────────────┐
; │ Increment the watchdog, but don't let │
; │ it wrap around. │
; └────────────────────────────────────────┘
MOV AL,[DMAIrqWatch]
CMP AL,250
JNC SHORT @@noinc
INC [DMAIrqWatch]
@@noinc:
; ┌────────────────────────────────────────────────┐
; │ Do the final stuff: Pop registers, restore the │
; │ stack, and exit. │
; └────────────────────────────────────────────────┘
POP DS
POP ES
POPA
IRET
MASM
COMMENT ~
kk:
CLI ; Just for safety's sake.
; ┌─────────────────────────┐
; │ Startup: │
; │ │
; │ - Save the registers. │
; └─────────────────────────┘
PUSHA
PUSH ES
PUSH DS
MOV AX,SEG Sounding
MOV DS,AX
@@DoSystemClock:
; ┌────────────────────────────────────────────────────┐
; │ Check if the old interrupt routine must be called. │
; └────────────────────────────────────────────────────┘
MOV AX,[SystemClockIncr]
ADD [SystemClockCount],AX
JNC SHORT @@NoSysClk
; ┌───────────────┐
; │ If so, do it. │
; └───────────────┘
PUSHF
CALL [OldTimerHandler]
JMP SHORT @@SystemClkDone
@@NoSysClk:
; ┌──────────────────────────────────┐
; │ Else, signal the EOI to the PIC. │
; └──────────────────────────────────┘
MOV AL,20h
OUT 20h,AL
@@SystemClkDone:
CLI
; ┌─────────────────────────────────────────┐
; │ First we check if the DMA operation is │
; │ requested to stop. If so, we signal the │
; │ stopping of the DMA and jump to the old │
; │ IRQ-checking part. │
; └─────────────────────────────────────────┘
MOV AL,[DMAStop]
AND AL,AL
JZ SHORT @@notstop
; MOV [DMAStopped],AL
MOV [DeviceIdling],AL
JMP SHORT @@end
@@notstop:
; ┌─────────────────────────────────────────┐
; │ Now, we check the IRQ watchdog, just in │
; │ case we need to kick the card. │
; └─────────────────────────────────────────┘
MOV AL,[DMAIrqWatch]
CMP AL,200
JC SHORT @@notwatch
; CALL [DeviceKickRut]
@@notwatch:
; ┌─────────────────────────────────────────┐
; │ If the device is said to be idle, reset │
; │ the timer. This is to protect the timer │
; │ period from being modified. │
; └─────────────────────────────────────────┘
MOV AL,[DeviceIdling]
AND AL,AL
JZ SHORT @@notidling
; CALL InitTimer
@@notidling:
; ┌────────────────────────────────────────┐
; │ Signal that the device is not idling, │
; │ and fill a bit more of the DMA buffer. │
; └────────────────────────────────────────┘
MOV AL,[CS:DMASema]
AND AL,AL
JNZ @@end
INC [CS:DMASema]
STI
@@loop:
PUSH DS
MOV AX,0B800h
MOV DS,AX
INC [WORD PTR DS:90*4];
POP DS
MOV [DevSS],SS
MOV [DevSP],SP
MOV DX,DS
MOV SS,DX
MOV SP,OFFSET DevStack + StackSize
XOR AL,AL
MOV [DeviceIdling],AL
;SetBorder 0, 63, 63
STI
CALL DMADoGetBuff
CLI
;SetBorder 0, 0, 63
; ┌─────────────────────────────────────┐
; │ Call the periodic process and exit. │
; └─────────────────────────────────────┘
STI
CALL [PeriodicProc]
CLI
MOV SS,[DevSS]
MOV SP,[DevSP]
MOV AL,[CS:DeviceIdCount]
AND AL,AL
; JZ @@loop
DEC [CS:DMASema]
@@end:
; ┌────────────────────────────────────────┐
; │ Increment the watchdog, but don't let │
; │ it wrap around. │
; └────────────────────────────────────────┘
MOV AL,[DMAIrqWatch]
CMP AL,250
JNC SHORT @@noinc
INC [DMAIrqWatch]
@@noinc:
; ┌────────────────────────────────────────────────┐
; │ Do the final stuff: Pop registers, restore the │
; │ stack, and exit. │
; └────────────────────────────────────────────────┘
POP DS
POP ES
POPA
IRET
~
IDEAL
PUBLIC NullTimerHandler
NullTimerHandler:
PUSHA
PUSH DS
PUSH ES
MOV AX,SEG Sounding
MOV DS,AX
MOV [DevSS],SS
MOV [DevSP],SP
MOV DX,DS
MOV SS,DX
MOV SP,OFFSET DevStack + StackSize
@@DoSystemClock:
; ┌────────────────────────────────────────────────────┐
; │ Check if the old interrupt routine must be called. │
; └────────────────────────────────────────────────────┘
MOV AX,[SystemClockIncr]
ADD [SystemClockCount],AX
JNC SHORT @@NoSysClk
; ┌───────────────┐
; │ If so, do it. │
; └───────────────┘
PUSHF
CALL [OldTimerHandler]
JMP SHORT @@SystemClkDone
@@NoSysClk:
; ┌──────────────────────────────────┐
; │ Else, signal the EOI to the PIC. │
; └──────────────────────────────────┘
MOV AL,20h
OUT 20h,AL
@@SystemClkDone:
CALL [PeriodicProc]
MOV SS,[DevSS]
MOV SP,[DevSP]
POP ES
POP DS
POPA
IRET
; ┌──────────────────────────────────────────────────────────────────────────┐
; │ │
; │ ROUTINE: NullDevRut │
; │ │
; │ Do-nothing routine for the unused device services. │
; │ │
; └──────────────────────────────────────────────────────────────────────────┘
NullDevRut:
RET
INCLUDE "DEVSB.INC"
INCLUDE "DEVSPKR.INC"
INCLUDE "DEVDAC.INC"
END